/* init/main.c 
 * 
 * This file is part of xnix. 
 * 
 * XNIX is free software: you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License as published by 
 * the Free Software Foundation, either version 3 of the License, or 
 * (at your option) any later version. 
 * 
 * XNIX is distributed in the hope that it will be useful, 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
 * GNU General Public License for more details. 
 * 
 * You should have received a copy of the GNU General Public License 
 * along with XNIX. If not, see <https://www.gnu.org/licenses/>
 */ 




#include <kernel/init.h>
#include <kernel/module.h>

#include <kernel/klist.h>
#include <kernel/mm.h>

#include <sys/types.h>



int do_init_calls(void);


int __init init(void) {
	struct klist_node *node;

	do_init_calls();
	
	node = mmp_bmb_alloc(klist_node_pool);
	node = mmp_bmb_alloc(klist_node_pool);
	node = mmp_bmb_alloc(klist_node_pool);

	mmp_bmb_free(node);

	node = mmp_bmb_alloc(klist_node_pool);

	node->next = NULL;

	return 0;
}



static void *init_call_levels[] = {
	&_init_call_arch, &_einit_call_arch, 
	&_init_call_kernel, &_einit_call_kernel, 
	&_init_call_modules, &_einit_call_modules, 
	NULL, NULL
};



/* 
 * call all functions in section _init_call, until finish. 
 *
 * _init_call defines in kernel.lds, it points to the start-address of 
 * section init_call. we put all initcall functions in that by the macro 
 * module_init(fn). that will make a new function pointer into that section. 
 *
 * if any function returns a non-zero return value, we return that too and init() will 
 * halt the cpu. 
 * */

int __init do_init_calls(void) {
	int error;
	int i;

	__uint64_t *start, *end;

	__uint64_t fn;
	__uint64_t *initcalls;

	for (i = 0; i < 6; i += 2) {
		start = init_call_levels[i];
		end = init_call_levels[i + 1];

		int ncalls = end - start;

		for (initcalls = start; ncalls; initcalls++, ncalls--) {
			fn = *initcalls;

			if (!fn) break;

			if ((error = ((int (*) (void)) fn)())) 
				return error;
		}
	}

	return 0;
}



/* this is a builtin function, we use this 
 * when there is a problem */

void __stack_chk_fail(void) {
	for (;;);

	return;
}


